class ATR
    attr_reader :atr_bytes
    # provide a string of bytes to init this object.
    def initialize atr_bs
      @atr_bytes = atr_bs.getBytes
      @atr_string = atr_bs.toString(HEX)
      @ta=Hash.new
      @tb=Hash.new
      @tc=Hash.new
      @td=Hash.new
      decode  
    end
    
    # ATR spec:
    # TS : initial 
    #   3F = inverse logic
    #   3B = direct logic
    # T0 : format
    #   |7|6|5|4||3|2|1|0|
    #   bits 4 through 7 indicate presence of TA1, TB1, TC1, TD1 respectively 
    #   bits 0-3 are the length of the "historical data"
    #
    #   TA1...TD1, if present follow T0
    #
    #   TAi, TBi, and TCi have codified sematics, a possible TDi field signals the
    #   existance of further TAi+1... fields.
    #
    #   |7|6|5|4||3|2|1|0|
    #   
    #   where 4, 5 and 6 signal he presesence of TAx, TBx, TCx, TDx.
    #
    #   finally the last bytes are "historical data" followed by a single byte checksum.
    def decode
      pos = 0
      @ts = @atr_bytes[pos]
      case @ts
      when 0x3F then 
        @ts_d="inverse"
      when 0x3B then 
        @ts_d="direct"
      else  
        @ts_d = "invalid"
      end

      @t0 = @atr_bytes[pos+=1]
      
      ta, tb, tc,td, @hist_data_len = decode_TD 0, pos
      
      i=1
      @max_i = 0
      while ta || tb || tc || td
        @max_i = i
        decodeTA i, pos+=1 if ta 
        decodeTB i, pos+=1 if tb 
        decodeTC i, pos+=1 if tc 
        if td
          ta, tb, tc, td = decode_TD i, pos+=1
        else
          break   
        end
        i+=1
      end
      
      @historical_data = @atr_bytes[pos+=1, @hist_data_len]
    end
  
    def decodeTA i, pos
      @ta ||= Hash.new
      @ta[i]=@atr_bytes[pos] 
    end
    
    def decodeTB i, pos
      @tb ||= Hash.new
      @tb[i]=@atr_bytes[pos] 
    end

    def decodeTC i, pos
      @tc ||= Hash.new
      @tc[i]=@atr_bytes[pos] 
    end

    # decodes a byte in the form:
    #   |7|6|5|4||3|2|1|0|
    # and returns
    # [TA?, B?, TC?, TD?, num]
    def decode_TD i, pos
            byte = @atr_bytes[pos]
            @td ||= Hash.new
            @td[i]=byte

            [
              (byte & 0x10)!=0,
              (byte & 0x20)!=0,
              (byte & 0x40)!=0,
              (byte & 0x80)!=0,
              byte & 0x0F
            ]
    end

    def to_s
      str = <<HELLO
ATR #{@atr_string}  
  TS (#{"%X"%@ts}) = #{@ts_d}
  T0 (#{"%X"%@t0}) = #{"%08b"%@t0} = #{@hist_data_len} byte [historical characters]

HELLO
    
      1.upto(@max_i) {|i|
        str << "i=#{i}\n"
        str << label_i_hex_bin("TA", i, @ta[i])  
        str << label_i_hex_bin("TB", i, @tb[i]) 
        str << label_i_hex_bin("TC", i, @tc[i]) 
        str << label_i_hex_bin("TD", i, @td[i]) 
      }
      
      if @historical_data 
        str << "\nHistorical Data = " 
        str << HexString.hexifyByteArray(@historical_data)
      end

      str
    end


    def label_i_hex_bin label, i, byte 
      byte == nil ? "" : "  %s%d(%02x) = %08b\n" % [label, i, byte, byte]
    end
end


